/*
 * Vigenere.h
 *
 *  Created on: Nov 20, 2011
 *      Author: belu
 */
#include "Vigenere.h"

Vigenere::Vigenere(Properties* props){
	symbols = props->get("VIGNERE_SYMBOLS") + " ";
	//symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789()%-:>";
	//key = "datos";
	key = props->get("VIGNERE_KEY");
}

Vigenere::~Vigenere(){
}

string Vigenere::getSymbols(){
	return symbols;
}

vector<int> Vigenere::phi(string message){
	stringstream ssAlfabeto;
	const char* msgAlfabeto = symbols.c_str();
	unsigned long msgAlfabeto_len = strlen(msgAlfabeto);
		
	stringstream ss;
	const char* msg = message.c_str();
	unsigned long msg_len = strlen(msg);
	
	vector<int> mjeInt;
	
	for (unsigned int i = 0; i < msg_len; i++) {
		char c1 = msg[i];
		
		for(unsigned int j = 0; j<msgAlfabeto_len; j++){
			char c2 = msgAlfabeto[j];
			
			if(c1 == c2){
				mjeInt.push_back(j);
				j = msgAlfabeto_len;
			}
		}		
	}
	return mjeInt;
}

/*
 * Devuelve el string correspondiente al vector<int> pasado como parametro
 */
string Vigenere::obtenerString(vector<int> mjeEncriptado){
	string mjeEncriptadoS;
	string s;
	for(unsigned int i= 0; i< mjeEncriptado.size(); i++){
		char letra = this->symbols.at(mjeEncriptado[i]);
		
		if(letra == ' '){
			s = " ";
		}
		else{
			stringstream ss;
			ss << letra;
			ss >> s;
		}
		mjeEncriptadoS.append(s);
		}
	return mjeEncriptadoS;
}

/*
 * Encriptacion con Vigenere
 * Defino el alfabeto con una cantidad de simbolos q.
 * Se obtiene la posicion de cada letra del mensaje dentro del alfabeto. -> M = (m1 m2..)
 * Lo mismo para la clave. -> K = (k1 k2..)
 * Ek(m) = (phi1 phi2...) 
 * con phi(i) = (mje(i) + k(i)) mod q
 */
string Vigenere::encrypt(string message){
	string mjeE;
	
	vector<int> mjeInt = phi(message);
	vector<int> claveInt = phi(key);
	
	vector<int> mjeEncriptado = mjeInt;
	
	unsigned long longVectorClave = claveInt.size();
	int j = 0;
	
	for (unsigned long i=0; i< mjeInt.size(); i++){
		if(i<longVectorClave){	
			mjeEncriptado.at(i) = mjeInt.at(i) + claveInt.at(j);
			j += 1;
		}
		else {
			j=0;
			mjeEncriptado.at(i) = mjeInt.at(i) + claveInt.at(j);
		}
		
		if(mjeEncriptado[i]>(symbols.size()-1)){
			mjeEncriptado.at(i)-= symbols.size()-1; 
		}
	}
	mjeE = obtenerString(mjeEncriptado);
	
	return mjeE;
}

bool Vigenere::encrypt(string sourceFile, string destFile) {
	ifstream _file;
	_file.open(sourceFile.c_str(),fstream::in);

	ofstream fileEncrypted;
	fileEncrypted.open(destFile.c_str(),fstream::out|fstream::trunc);

	if (!_file.is_open()) {
		cerr << "Error archivo origen. "<< sourceFile <<endl;
		return false;
	}

	if 	(!fileEncrypted.is_open()) {
		cerr << "Error archivo encriptado " << destFile <<endl;
		return false;
	}

	string aLine;
	string bLine;
	while (getline(_file, aLine)) {
		bLine = encrypt(aLine);
		fileEncrypted << bLine << endl;
	}

	fileEncrypted.flush();
	fileEncrypted.close();
	_file.close();
	return true;
}

/* Desencriptar con Vigenere
 * Dk(m) = (phi(-1)1 phi(-2)2..)
 * con phi(-1)i = (phi(i)-k(i)) mod q 
 */
string Vigenere::decrypt(string msg){
	string mjeD;
	
	vector<int> mjeInt = phi(msg);
	vector<int> claveInt = phi(key);
		
	vector<int> mjeDesencriptado = mjeInt;
	unsigned long longVectorClave = claveInt.size();
	int j = 0;
	
	for (unsigned long i=0; i< mjeInt.size(); i++){
		if(i<longVectorClave){
			mjeDesencriptado.at(i) = mjeInt.at(i) - claveInt.at(j);
			j += 1;
		}
		else {
			j=0;
			mjeDesencriptado.at(i) = mjeInt.at(i) - claveInt.at(j);
		}
		
		if(mjeDesencriptado.at(i)<=0){
			mjeDesencriptado.at(i) += symbols.size()-1;
		}
	}

	mjeD = obtenerString(mjeDesencriptado);	
	
	return mjeD;
}

bool Vigenere::decrypt(string sourceFile, string destFile) {
	ifstream encryptedFile;
	encryptedFile.open(sourceFile.c_str());

	ofstream plainFile;
	plainFile.open(destFile.c_str(),fstream::out|fstream::trunc);

	if (plainFile.is_open() == false || encryptedFile.is_open() == false) {
		return false;
	}

	string aLine;
	string bLine;
	while (getline(encryptedFile, aLine)) {
		bLine = decrypt(aLine);
		plainFile << bLine << endl;
	}

	plainFile.flush();
	plainFile.close();

	encryptedFile.close();

	return true;
}

